/*
   Copyright 2009 Abdulla Abdurakhmanov (abdulla@latestbit.com)
   Original sources are available at www.latestbit.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#ifndef SYSTEMEXCEPTION_HPP
#define SYSTEMEXCEPTION_HPP

#include <string>
#include <exception>
#include <vector>
#include "cpputils/CppUtilsDefinitions.hpp"
#include "cpputils/OsSpecific.hpp"

namespace cpputils {
	class SystemException : public std::logic_error {
	public:
		typedef std::vector<std::string> BacktraceSymbols;

	public:
		inline SystemException(const std::string& msg): std::logic_error(msg) { setupBacktrace(); }
		inline SystemException(const boost::format& formattedMsg): std::logic_error(formattedMsg.str()) { setupBacktrace(); }
		inline SystemException(const std::string& message, const std::exception& cause ) : std::logic_error(message+"\n"+cause.what()) { setupBacktrace(); };
		inline SystemException(const boost::format& formattedMsg, const std::exception& cause ): std::logic_error(formattedMsg.str()+"\n"+cause.what()) {};
		inline SystemException(const std::exception& cause): std::logic_error(cause.what()) {};

		inline virtual ~SystemException() throw() {}

		inline const BacktraceSymbols& getBacktrace() const {
			return m_aBacktrace;
		}

		inline void printBacktrace() const {
			std::cout << "Backtrace [BEGIN] " <<std::endl;
			for(BacktraceSymbols::const_iterator it = m_aBacktrace.begin(); it!=m_aBacktrace.end(); it++) {
				std::cout << "-->" << *it << std::endl;
			}
			std::cout << "[END] " <<std::endl;
		}

	protected:
		inline SystemException() : std::logic_error("Unknown system exception") { setupBacktrace(); };
	protected:
		inline void setupBacktrace() {
			#ifdef HAVE_BACKTRACE_SYMBOLS
				#ifndef WIN32
				 void* pCallstack[256];
				 int nFrames = backtrace(pCallstack, 256);
				 char** pCallstackSyms = backtrace_symbols(pCallstack, nFrames);
				 for(int i=0; i<nFrames; i++) {
					m_aBacktrace.push_back(pCallstackSyms[i]);
				 }
				 free(pCallstackSyms);
				#else

				#endif
			#endif
		}
	protected:
#ifdef HAVE_BACKTRACE_SYMBOLS
		BacktraceSymbols m_aBacktrace;
#else
		CPPU_DLLPRFX const static BacktraceSymbols m_aBacktrace;
#endif
	};
}

#endif // SYSTEMEXCEPTION_HPP
